<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Njmon Charts</title>
    <!-- 引入 ECharts -->
    <script src="./js/echarts.min.js"></script>
    <!-- 引入 jQuery -->
    <script src="./js/jquery.min.js"></script>
	 <!-- 添加 CSS 样式 -->
	<style>
		body {
			font-family: Arial, sans-serif;
			margin: 10px;
		}
		#buttonsContainer {
		    display: flex;
		    overflow-x: auto;
		}
		.div-inline {
		    display: inline-block; /* 或者使用 display: inline; */
		    display: flex;
		}
		button {
			background-color: #007cb5; /* Green */
			border: none;
			color: white;
			padding: 10px 10px;
			text-align: center;
			text-decoration: none;
			display: inline-block;
			margin: 1px;
			cursor: pointer;
			
			/* border-radius: 5px; */
			white-space: nowrap; /* 新增属性，防止文本换行 */
			overflow: hidden; /* 新增属性，隐藏超出的部分 */
			text-overflow: ellipsis; /* 新增属性，显示省略号 */
		}
		button:hover {
			background-color: #7bcaff;
		}
		button.active {
			background-color: #45a049; /* 更深的绿色 */
		}
		table {
		    width: 100%;
		    border-collapse: collapse;
		}
		th, td {
		    border: 1px solid #ddd;
		    padding: 8px;
		    text-align: left;
		}
		th {
		    background-color: #f2f2f2;
		}
	</style>
</head>
<body>
    <div id="buttonsContainer">
    </div>
    <div id="metricsChart" style="width: 100%;height:800px;"></div>
    <div id="sysInfo">
		<h1>System Information</h1>
		<table id="sysInfoTable">
			<thead>
				<tr>
					<th style="width: 15%;">Field</th>
					<th style="width: 15%;">Section</th>
					<th>Value</th>
				</tr>
			</thead>
			<tbody>
			</tbody>
		</table>
	</div>
    <script>
        // 示例 JSON 数据
        // const jsonData = {"Occupy":{"cpu_total":{"guest":[0,0,0,0,0,0,0,0,0,0],"guestnice":[0,0,0,0,0,0,0,0,0,0],"hardirq":[0,0,0,0,0,0,0,0,0,0],"idle":[97.917,97.178,97.595,93.062,92.26,96.785,96.807,97.284,96.096,97.613],"iowait":[0,0,0,0,0,0,0,0,0,0],"nice":[0,0,0,0,0,0,0,0,0,0],"softirq":[0,0,0,0,0.25,0,0,0,0,0],"steal":[0,0,0,0,0,0,0,0,0,0],"sys":[0.5,0.25,0.494,1.264,1.5,0.25,0.25,0.499,0.751,0.501],"user":[1.998,1.249,1.235,4.046,4.25,2.001,1.501,1.746,2.002,1.502]},"cpus":{"cpu0":{"guest":[0,0,0,0,0,0,0,0,0,0],"guestnice":[0,0,0,0,0,0,0,0,0,0],"hardirq":[0,0,0,0,0,0,0,0,0,0],"idle":[97.917,97.927,97.842,94.073,94.01,97.035,96.057,98.781,96.096,97.112],"iowait":[0,0,0,0,0,0,0,0,0,0],"nice":[0,0,0,0,0,0,0,0,0,0],"softirq":[0,0,0,0,0,0,0,0,0,0],"steal":[0,0,0,0,0,0,0,0,0,0],"sys":[0,0,0.988,1.012,1,0,0,0.998,1.001,0],"user":[1.998,0.999,0,3.035,4,2.001,2.001,0.998,2.002,2.002]},"cpu1":{"guest":[0,0,0,0,0,0,0,0,0,0],"guestnice":[0,0,0,0,0,0,0,0,0,0],"hardirq":[0,0,0,0,0,0,0,0,0,0],"idle":[97.917,97.927,96.853,94.073,93.01,97.035,99.058,97.783,95.095,97.112],"iowait":[0,0,0,0,0,0,0,0,0,0],"nice":[0,0,0,0,0,0,0,0,0,0],"softirq":[0,0,0,0,0,0,0,0,0,0],"steal":[0,0,0,0,0,0,0,0,0,0],"sys":[0,0.999,0,1.012,2,0,0,0,1.001,1.001],"user":[1.998,0.999,1.977,3.035,4,2.001,1.001,0.998,2.002,2.002]},"cpu2":{"guest":[0,0,0,0,0,0,0,0,0,0],"guestnice":[0,0,0,0,0,0,0,0,0,0],"hardirq":[0,0,0,0,0,0,0,0,0,0],"idle":[98.916,96.928,96.853,95.085,91.01,96.035,95.056,96.785,97.097,99.115],"iowait":[0,0,0,0,0,0,0,0,0,0],"nice":[0,0,0,0,0,0,0,0,0,0],"softirq":[0.999,0,0,0,0,0,0,0,0,0],"steal":[0,0,0,0,0,0,0,0,0,0],"sys":[0.999,0,0.988,1.012,2,0,0,0.998,1.001,0],"user":[0.999,0.999,1.977,2.023,7.001,2.001,2.001,1.996,1.001,1.001]},"cpu3":{"guest":[0,0,0,0,0,0,0,0,0,0],"guestnice":[0,0,0,0,0,0,0,0,0,0],"hardirq":[0,0,0,0,0,0,0,0,0,0],"idle":[96.918,95.929,97.842,90.027,90.01,97.035,98.058,95.787,95.095,98.114],"iowait":[0,0,0,0,0,0,0,0,0,0],"nice":[0,0,0,0,0,0,0,0,0,0],"softirq":[0,0,0,0,0,0,0,0,0,0],"steal":[0,0,0,0,0,0,0,0,0,0],"sys":[0,0.999,0,2.023,2,0,0,0.998,0,1.001],"user":[2.997,1.999,0.988,7.081,4,1,1.001,2.993,2.002,2.002]}},"disks":{"sda":{"reads":[0,0,0,0,0,0,0,0,0,0],"rkb":[0,0,0,0,0,0,0,0,0,0],"rmerge":[0,0,0,0,0,0,0,0,0,0],"rmsec":[0,0,0,0,0,0,0,0,0,0],"wkb":[0,3.997,7.906,8.092,416.044,8.003,8.005,11.973,12.012,20.023],"wmerge":[0,0,0,0,0,0,0,0,0,0],"wmsec":[0,0,0,0,5.001,0,0,0,0,2.002],"writes":[0,0.999,0.988,1.012,23.002,1,1.001,0.998,1.001,3.003],"xfers":[0,0.999,0.988,1.012,23.002,1,1.001,0.998,1.001,3.003]},"sr0":{"reads":[0,0,0,0,0,0,0,0,0,0],"rkb":[0,0,0,0,0,0,0,0,0,0],"rmerge":[0,0,0,0,0,0,0,0,0,0],"rmsec":[0,0,0,0,0,0,0,0,0,0],"wkb":[0,0,0,0,0,0,0,0,0,0],"wmerge":[0,0,0,0,0,0,0,0,0,0],"wmsec":[0,0,0,0,0,0,0,0,0,0],"writes":[0,0,0,0,0,0,0,0,0,0],"xfers":[0,0,0,0,0,0,0,0,0,0]}},"filesystems":{"/dev/mapper/centos-root":{"fs_avail":[855272,855272,855272,855272,855272,855272,855272,855272,855272,855272],"fs_bavail":[218949856,218949858,218949857,218949857,218949844,218949844,218949844,218949843,218949843,218949843],"fs_bfree":[218949856,218949858,218949857,218949857,218949844,218949844,218949844,218949843,218949843,218949843],"fs_blocks":[233194240,233194240,233194240,233194240,233194240,233194240,233194240,233194240,233194240,233194240],"fs_bsize":[4096,4096,4096,4096,4096,4096,4096,4096,4096,4096],"fs_files":[466616320,466616320,466616320,466616320,466616320,466616320,466616320,466616320,466616320,466616320],"fs_files_free":[465786169,465786169,465786169,465786169,465786169,465786169,465786169,465786169,465786169,465786169],"fs_free_mb":[855272,855272,855272,855272,855272,855272,855272,855272,855272,855272],"fs_freqs":[0,0,0,0,0,0,0,0,0,0],"fs_full_percent":[6.108,6.108,6.108,6.108,6.108,6.108,6.108,6.108,6.108,6.108],"fs_namelength":[255,255,255,255,255,255,255,255,255,255],"fs_passno":[0,0,0,0,0,0,0,0,0,0],"fs_size_mb":[910915,910915,910915,910915,910915,910915,910915,910915,910915,910915],"fs_used_mb":[55643,55643,55643,55643,55643,55643,55643,55643,55643,55643]},"/dev/mapper/centos-temp":{"fs_avail":[5415,5415,5415,5415,5415,5415,5415,5415,5415,5415],"fs_bavail":[1386411,1386411,1386411,1386411,1386411,1386411,1386411,1386411,1386411,1386411],"fs_bfree":[1386411,1386411,1386411,1386411,1386411,1386411,1386411,1386411,1386411,1386411],"fs_blocks":[1570304,1570304,1570304,1570304,1570304,1570304,1570304,1570304,1570304,1570304],"fs_bsize":[4096,4096,4096,4096,4096,4096,4096,4096,4096,4096],"fs_files":[3145728,3145728,3145728,3145728,3145728,3145728,3145728,3145728,3145728,3145728],"fs_files_free":[3145523,3145523,3145523,3145523,3145523,3145523,3145523,3145523,3145523,3145523],"fs_free_mb":[5415,5415,5415,5415,5415,5415,5415,5415,5415,5415],"fs_freqs":[0,0,0,0,0,0,0,0,0,0],"fs_full_percent":[11.711,11.711,11.711,11.711,11.711,11.711,11.711,11.711,11.711,11.711],"fs_namelength":[255,255,255,255,255,255,255,255,255,255],"fs_passno":[0,0,0,0,0,0,0,0,0,0],"fs_size_mb":[6134,6134,6134,6134,6134,6134,6134,6134,6134,6134],"fs_used_mb":[719,719,719,719,719,719,719,719,719,719]},"/dev/sda1":{"fs_avail":[4620,4620,4620,4620,4620,4620,4620,4620,4620,4620],"fs_bavail":[1182813,1182813,1182813,1182813,1182813,1182813,1182813,1182813,1182813,1182813],"fs_bfree":[1182813,1182813,1182813,1182813,1182813,1182813,1182813,1182813,1182813,1182813],"fs_blocks":[1308160,1308160,1308160,1308160,1308160,1308160,1308160,1308160,1308160,1308160],"fs_bsize":[4096,4096,4096,4096,4096,4096,4096,4096,4096,4096],"fs_files":[2621440,2621440,2621440,2621440,2621440,2621440,2621440,2621440,2621440,2621440],"fs_files_free":[2621064,2621064,2621064,2621064,2621064,2621064,2621064,2621064,2621064,2621064],"fs_free_mb":[4620,4620,4620,4620,4620,4620,4620,4620,4620,4620],"fs_freqs":[0,0,0,0,0,0,0,0,0,0],"fs_full_percent":[9.582,9.582,9.582,9.582,9.582,9.582,9.582,9.582,9.582,9.582],"fs_namelength":[255,255,255,255,255,255,255,255,255,255],"fs_passno":[0,0,0,0,0,0,0,0,0,0],"fs_size_mb":[5110,5110,5110,5110,5110,5110,5110,5110,5110,5110],"fs_used_mb":[490,490,490,490,490,490,490,490,490,490]}},"networks":{"eth0":{"ibytes":[449.617,419.689,326.139,333.809,494.052,390.141,390.23,329.268,330.331,330.383],"idrop":[0,0,0,0,0,0,0,0,0,0],"ififo":[0,0,0,0,0,0,0,0,0,0],"ipackets":[3.997,2.998,1.977,2.023,4,3.001,3.002,1.996,2.002,2.002],"obytes":[359.694,299.778,237.192,182.078,344.036,240.087,240.141,179.601,180.181,180.209],"odrop":[0,0,0,0,0,0,0,0,0,0],"ofifo":[0,0,0,0,0,0,0,0,0,0],"opackets":[4.996,3.997,2.965,2.023,4,3.001,3.002,1.996,2.002,2.002]},"lo":{"ibytes":[287.755,199.852,197.66,291.324,200.021,304.11,200.118,199.557,200.201,200.232],"idrop":[0,0,0,0,0,0,0,0,0,0],"ififo":[0,0,0,0,0,0,0,0,0,0],"ipackets":[4.996,3.997,3.953,5.058,4,6.002,4.002,3.991,4.004,4.005],"obytes":[287.755,199.852,197.66,291.324,200.021,304.11,200.118,199.557,200.201,200.232],"odrop":[0,0,0,0,0,0,0,0,0,0],"ofifo":[0,0,0,0,0,0,0,0,0,0],"opackets":[4.996,3.997,3.953,5.058,4,6.002,4.002,3.991,4.004,4.005]},"team0":{"ibytes":[393.665,377.72,298.467,305.486,438.046,348.126,348.205,301.33,302.303,302.35],"idrop":[0,0,0,0,0,0,0,0,0,0],"ififo":[0,0,0,0,0,0,0,0,0,0],"ipackets":[3.997,2.998,1.977,2.023,4,3.001,3.002,1.996,2.002,2.002],"obytes":[329.719,275.796,219.403,182.078,344.036,222.08,222.131,179.601,180.181,180.209],"odrop":[0,0,0,0,0,0,0,0,0,0],"ofifo":[0,0,0,0,0,0,0,0,0,0],"opackets":[4.996,3.997,2.965,2.023,4,3.001,3.002,1.996,2.002,2.002]},"tunl0":{"ibytes":[0,0,0,0,0,0,0,0,0,0],"idrop":[0,0,0,0,0,0,0,0,0,0],"ififo":[0,0,0,0,0,0,0,0,0,0],"ipackets":[0,0,0,0,0,0,0,0,0,0],"obytes":[0,0,0,0,0,0,0,0,0,0],"odrop":[0,0,0,0,0,0,0,0,0,0],"ofifo":[0,0,0,0,0,0,0,0,0,0],"opackets":[0,0,0,0,0,0,0,0,0,0]}},"proc_meminfo":{"Active":[4334984,4335388,4335732,4335864,4336348,4336252,4336428,4337144,4337364,4337844],"Active_file":[895384,895372,895372,895372,895372,895376,895376,895376,895376,895376],"Buffers":[0,0,0,0,0,0,0,0,0,0],"Cached":[2528016,2528008,2528012,2528012,2528012,2528016,2528016,2528020,2528020,2528020],"Inactive":[2393484,2393488,2393492,2393492,2393492,2393492,2393492,2393496,2393496,2393496],"Inactive_file":[1595880,1595884,1595888,1595888,1595888,1595888,1595888,1595892,1595892,1595892],"MemAvailable":[2834988,2834584,2834216,2833860,2833412,2833492,2833120,2832364,2831992,2832116],"MemFree":[173728,173332,172960,172604,172156,172232,171860,171100,170712,170836],"MemTotal":[8008496,8008496,8008496,8008496,8008496,8008496,8008496,8008496,8008496,8008496],"SwapFree":[8385780,8385780,8385780,8385780,8385780,8385780,8385780,8385780,8385780,8385780],"SwapTotal":[8388604,8388604,8388604,8388604,8388604,8388604,8388604,8388604,8388604,8388604]},"timestamp":{"UTC":["2024-08-30T08:39:58","2024-08-30T08:39:59","2024-08-30T08:40:00","2024-08-30T08:40:01","2024-08-30T08:40:02","2024-08-30T08:40:03","2024-08-30T08:40:04","2024-08-30T08:40:05","2024-08-30T08:40:06","2024-08-30T08:40:07"],"datetime":["2024-08-30T16:39:58","2024-08-30T16:39:59","2024-08-30T16:40:00","2024-08-30T16:40:01","2024-08-30T16:40:02","2024-08-30T16:40:03","2024-08-30T16:40:04","2024-08-30T16:40:05","2024-08-30T16:40:06","2024-08-30T16:40:07"],"elapsed":[1.001,1.001,1.012,0.989,1,1,0.999,1.002,0.999,0.999],"execute_time":[0,0.016,0.016,0.015,0.015,0.018,0.015,0.016,0.016,0.015],"sleep_overrun":[0,0.001,0.013,0.001,0.001,0.001,0,0.002,0.001,0],"sleeping":[1,0.984,0.983,0.972,0.984,0.981,0.984,0.984,0.982,0.984],"snapshot_loop":[0,1,2,3,4,5,6,7,8,9],"snapshot_maxloops":[10,10,10,10,10,10,10,10,10,10],"snapshot_seconds":[1,1,1,1,1,1,1,1,1,1]}},"SysInfo":{"identity":{"fullhostname":"BJCADevice","hostname":"BJCADevice","ipaddress":"192.168.0.188","model":"VirtualBox","njmon_command":"/root/go/src/easyNmon/njmon -n -s 1 -c 10 ","njmon_mode":"njmon-JSON","njmon_version":"njmon4Linux-v83-CentOS-7-x86_64-njmon_linux_v83.c (Feb  1 2024)","userid":0,"username":"root","vendor":"innotek GmbH"},"lscpu":{"architecture":"x86_64","bogomips":"","byte_order":"Little Endian","cores_per_socket":"4","cpu_family":"","cpus":"4","model":"","model_name":"","numa_nodes":"","online_cpu_list":"0-3","sockets":"","stepping":"","threads_per_core":"1","vendor_id":""},"os_release":{"name":"CentOS Linux","pretty_name":"BJCADevice","version":"BJCADevice","version_id":"7"},"proc_version":{"version":"Linux version 3.10.0-1160.119.1.el7.x86_64 (mockbuild@kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) ) #1 SMP Tue Jun 4 14:43:51 UTC 2024"},"uptime":{"days":0,"hours":7,"minutes":17,"users":2}}};
		let jsonData = null;
		$.getJSON('data.json', function(data) {
			jsonData = data;
		})
		
        // 创建 ECharts 实例
        let myChart = null;
        // 初始化图表
        function initChart() {
            myChart = echarts.init(document.getElementById('metricsChart'));
        }

        // 提取数据
        function extractData(metricName, subMetricName) {
			if (subMetricName == ""){
				const data = jsonData.Occupy[metricName];
				const labels = jsonData.Occupy.timestamp.UTC;
				const series = [];
				
				// 处理数组数据
				if (Array.isArray(data)) {
				    return { labels, series: [{ name: metricName, data }] };
				}
				
				// 处理对象数据
				for (let key in data) {
				    if (Array.isArray(data[key])) {
				        series.push({ name: key, data: data[key] });
				    }
				}
				
				return { labels, series };
			}
            const data = jsonData.Occupy[metricName][subMetricName];
            const labels = jsonData.Occupy.timestamp.UTC;
            const series = [];

            // 处理数组数据
            if (Array.isArray(data)) {
                return { labels, series: [{ name: subMetricName, data }] };
            }

            // 处理对象数据
            for (let key in data) {
                if (Array.isArray(data[key])) {
                    series.push({ name: key, data: data[key] });
                }
            }

            return { labels, series };
        }

        // 显示图表
        function showChart(metricName, subMetricName) {
            const { labels, series } = extractData(metricName, subMetricName);
			var titleName = beautifyLabel(`${metricName}`);
			if (subMetricName != ""){
				titleName =  `${metricName}-${subMetricName}`;
			}
            // cpu的折线图上限值固定为100
		    const yAxisMax = containsCpu(metricName) ? 100 : null;
            const option = {
                title: {
                    text: titleName,
					left:'center',
					top:'20'
                },
				grid: {
				    left: '50',
				    right: '160',
				    bottom: '60',
				    containLabel: true
				},
				tooltip: {
				    trigger: 'axis'
				},
                toolbox: {
                    show: true,
				    feature: {
					  magicType: { type: ['line', 'bar'] },
					  restore: {},
					  saveAsImage: {}
				    },
					right:'180px'
                },
				dataZoom: [
				    {
				      start: 0,
				      end: 100
				    }
				],
                legend: {
                    data: series.map(s => s.name),
				    type: 'scroll',// 支持翻页
					orient: 'vertical',
					right: 20,
					top: 'center'
                },
                xAxis: {
                    type: 'category',
                    boundaryGap: false,
                    data: labels
                },
                yAxis:{
                    type: 'value',
					max: yAxisMax
                },
                series: series.map(s => ({
                    name: s.name,
                    type: 'line',
                    data: s.data
                }))
            };

            myChart.setOption(option);
        }

        // 初始化图表
        $(document).ready(function() {
            initChart();
            // 动态生成按钮
            const buttonContainer = $('#buttonsContainer');

            const metrics = ['System_Info', 'cpu_total', 'cpus', 'proc_meminfo', 'disks', 'networks', 'filesystems'];
            metrics.forEach(function(metric) {
                const buttonsForMetric = $('<div class="div-inline">').appendTo(buttonContainer);
			
                // 包含子项特殊处理 cpus, disks, networks, filesystems
                if (['cpus', 'disks', 'networks', 'filesystems'].includes(metric)) {
                    Object.keys(jsonData.Occupy[metric]).forEach(subMetric => {
						subname=getLastDirectoryPath(subMetric);
                        $('<button>').text(`${metric}-${subname}`).click(function() {
							clearActiveButtons();
							$(this).addClass('active');
							$('#metricsChart').show();
							$("#sysInfo").hide();
                            showChart(metric, subMetric);
                        }).appendTo(buttonsForMetric);
                    });
                } else if (['System_Info'].includes(metric)) {
					const label = beautifyLabel(metric);
					$('<button>').text(label).click(function() {
						clearActiveButtons();
						$(this).addClass('active');
						$('#metricsChart').hide();
                        $("#sysInfo").show();
					    populateTable(jsonData);
					}).appendTo(buttonsForMetric);				 
				}else {
					const label = beautifyLabel(metric);
                    $('<button>').text(label).click(function() {
						clearActiveButtons();
						$(this).addClass('active');
						$('#metricsChart').show();
						$("#sysInfo").hide();
                        showChart(metric, ""); 
                    }).appendTo(buttonsForMetric);
                }
            });

            // 默认显示第一个图表
			$('#buttonsContainer button').first().click();
			$('#buttonsContainer button').first().addClass('active');
			
			// 清除按钮的活动状态
			function clearActiveButtons() {
				$('#buttonsContainer button').removeClass('active');
			}
        });
		
		// 美化标签
		function beautifyLabel(label) {
			const labelMapping = {
				cpu_total: 'Total CPU',
				stat_counters: 'System Counters',
				loadavg: 'Load Average',
				proc_meminfo: 'Memory',
				cpus: 'CPU',
				disks: 'Disks',
				networks: 'Networks',
				filesystems: 'Filesystems',
			};
		
			return labelMapping[label] || label;
		}
		
		function getLastDirectoryPath(url) {
		    const urlParts = url.split('/');
		    const lastPart = urlParts.pop(); // 获取最后一个部分
		    return lastPart;
		}
		
		function containsCpu(str) {
		    const regex = /cpu/i; // i 表示不区分大小写
		    return regex.test(str);
		}
		
		// 动态生成表格内容
		function populateTable(jsonData) {
			const sysInfo = jsonData.SysInfo;
			const tbody = $('#sysInfoTable tbody');

			// 清空现有的表格内容
			tbody.empty();

			// 遍历 JSON 数据并生成表格行
			for (let section in sysInfo) {
				const sectionData = sysInfo[section];

				// 生成表格行
				for (let field in sectionData) {
					const value = sectionData[field];
					const row = $('<tr>');
					row.append($('<td>').text(`${section}`));
					row.append($('<td>').text(`${field}`));
					row.append($('<td>').text(value));

					// 将行添加到表格
					tbody.append(row);
				}
			}
		}

    </script>
</body>
</html>